import {trim,camelCase} from './utils'

const on = (function() {
    if( document.addEventListener ) {
      return function(elem, event, handler) {
        if (elem && event && handler) {
          elem.addEventListener(event, handler, false);
        }
      };
    } else {
      return function(elem, event, handler) {
        if (elem && event && handler) {
          elem.attachEvent('on' + event, handler);
        }
      };
    }
})();

const off = (function() {
    if( document.removeEventListener ) {
        return function(elem, event, handler) {
            if (elem && event) {
                elem.removeEventListener(event, handler, false);
            }
      };
    } else {
        return function(elem, event, handler) {
            if (elem && event) {
                elem.detachEvent('on' + event, handler);
            }
        };
    }
})();

const once = function(el, event, fn) {
    var listener = function() {
        if (fn) {
            fn.apply(this, arguments);
        }
        off(el, event, listener);
    };
    on(el, event, listener);
}

function hasClass(el, cls) {
    if (!el || !cls) return false;
    if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
    if (el.classList) {
        return el.classList.contains(cls);
    } else {
        return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
    }
}

function addClass(el, cls) {
    if (!el) return;
    var curClass = el.className;
    var classes = (cls || '').split(' ');
  
    for (var i = 0, j = classes.length; i < j; i++) {
        var clsName = classes[i];
        if (!clsName) continue;
    
        if (el.classList) {
            el.classList.add(clsName);
        } else if (!hasClass(el, clsName)) {
            curClass += ' ' + clsName;
        }
    }
    if (!el.classList) {
        el.className = curClass;
    }
}
  
function removeClass(el, cls) {
    if (!el || !cls) return;
    var classes = cls.split(' ');
    var curClass = ' ' + el.className + ' ';
  
    for (var i = 0, j = classes.length; i < j; i++) {
        var clsName = classes[i];
        if (!clsName) continue;
    
        if (el.classList) {
            el.classList.remove(clsName);
        } else if (hasClass(el, clsName)) {
            curClass = curClass.replace(' ' + clsName + ' ', ' ');
        }
    }
    if (!el.classList) {
        el.className = trim(curClass);
    }
}

const ieVersion = Number(document.documentMode);
const getStyle = ieVersion < 9 ? function(elem, styleName) {
    
    if (!elem || !styleName) return null;
    styleName = camelCase(styleName);
    if (styleName === 'float') {
        styleName = 'styleFloat';
    }
    try {
      switch (styleName) {
        case 'opacity':
            try {
                return elem.filters.item('alpha').opacity / 100;
            } catch (e) {
                return 1.0;
            }
        default:
            return (elem.style[styleName] || elem.currentStyle ? elem.currentStyle[styleName] : null);
      }
    } catch (e) {
        return elem.style[styleName];
    }
  } : function(elem, styleName) {
    
    if (!elem || !styleName) return null;
    styleName = camelCase(styleName);
    if (styleName === 'float') {
        styleName = 'cssFloat';
    }
    try {
        var computed = document.defaultView.getComputedStyle(elem, '');
        return elem.style[styleName] || computed ? computed[styleName] : null;
    } catch (e) {
        return elem.style[styleName];
    }
}

function setStyle(elem, styleName, value) {
    if (!elem || !styleName) return;
  
    if (typeof styleName === 'object') {
        for (var prop in styleName) {
            if (styleName.hasOwnProperty(prop)) {
            setStyle(elem, prop, styleName[prop]);
            }
        }
    } else {
        styleName = camelCase(styleName);
        if (styleName === 'opacity' && ieVersion < 9) {
            elem.style.filter = isNaN(value) ? '' : 'alpha(opacity=' + value * 100 + ')';
        } else {
            elem.style[styleName] = value;
        }
    }
}

function isScroll(el, vertical){
    
    const determinedDirection = vertical !== null || vertical !== undefined;
    const overflow = determinedDirection
      ? vertical
        ? getStyle(el, 'overflow-y')
        : getStyle(el, 'overflow-x')
      : getStyle(el, 'overflow');
  
    return overflow.match(/(scroll|auto)/);
}

function getScrollContainer(el, vertical){
  
    let parent = el;
    while (parent) {
        if ([window, document, document.documentElement].includes(parent)) {
            return window;
        }
        if (isScroll(parent, vertical)) {
            return parent;
        }
        parent = parent.parentNode;
    }  
    return parent;
}

function isInContainer(el, container){
    if ( !el || !container) return false;
  
    const elRect = el.getBoundingClientRect();
    let containerRect;
  
    if ([window, document, document.documentElement, null, undefined].includes(container)) {
        containerRect = {
            top: 0,
            right: window.innerWidth,
            bottom: window.innerHeight,
            left: 0
        };
    } else {
        containerRect = container.getBoundingClientRect();
    }
  
    return elRect.top < containerRect.bottom &&
      elRect.bottom > containerRect.top &&
      elRect.right > containerRect.left &&
      elRect.left < containerRect.right;
}

function getParent(el){

    if( !el ) return null;
    return el.parentNode || el.parentElement;
}

function getBoundingClientRect(element) {
    var rect = element.getBoundingClientRect();

    // whether the IE version is lower than 11
    var isIE = navigator.userAgent.indexOf("MSIE") != -1;

    // fix ie document bounding top always 0 bug
    var rectTop = isIE && element.tagName === 'HTML'
        ? -element.scrollTop
        : rect.top;

    return {
        left: rect.left,
        top: rectTop,
        right: rect.right,
        bottom: rect.bottom,
        width: rect.right - rect.left,
        height: rect.bottom - rectTop
    };
}

export default{
    on,
    off,
    once,
    hasClass,
    addClass,
    removeClass,
    getStyle,
    setStyle,
    isScroll,
    getScrollContainer,
    isInContainer,
    getParent,
    getBoundingClientRect
}